/*****************************************************************
 MYD Engine v0.1

 file: myd_renderer.cpp
 Created: 11/05/09 Re-created: 09/07/09
*****************************************************************/

#include "myd_renderer.h"
#include "myd_texture.h"

using namespace myd;

//-----------------------------------------------------------------InitDX
bool Renderer::initDX()
{
	D3Dobject = Direct3DCreate9(D3D_SDK_VERSION);

	D3DPRESENT_PARAMETERS d3dPP;
	ZeroMemory(&d3dPP, sizeof(d3dPP));

	D3DDISPLAYMODE displayMode;
	
	HRESULT hr = D3Dobject->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &displayMode);

	d3dPP.Windowed = TRUE;
    d3dPP.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dPP.hDeviceWindow = m_hWnd;
	
	/*/backbuffer stencil etc
	d3dPP.BackBufferFormat = D3DFMT_X8R8G8B8;
    d3dPP.BackBufferWidth = 800;
    d3dPP.BackBufferHeight = 600;
    d3dPP.EnableAutoDepthStencil = TRUE;
    d3dPP.AutoDepthStencilFormat = D3DFMT_D16;*/

/*/--------------------------------------
//ANTIALIASING

	DWORD totalMulti;
	D3Dobject->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT,
										D3DDEVTYPE_HAL,
										displayMode.Format,
										true,
										D3DMULTISAMPLE_NONMASKABLE,
										&totalMulti);
	{
		d3dPP.MultiSampleType = D3DMULTISAMPLE_NONMASKABLE;
		d3dPP.MultiSampleQuality = totalMulti - 1;
	}
//--------------------------------------*/

	hr = D3Dobject->CreateDevice(D3DADAPTER_DEFAULT,
						   D3DDEVTYPE_HAL,
						   m_hWnd,
						   D3DCREATE_SOFTWARE_VERTEXPROCESSING,
						   &d3dPP,
						   &D3Ddevice);
	
	if (!colorBuffer.create(D3Ddevice, true)){
		return false;
	}

	//filters
	D3Ddevice->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR);
	D3Ddevice->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_ANISOTROPIC);
	//D3Ddevice->SetSamplerState(0,D3DSAMP_MIPFILTER,D3DTEXF_LINEAR);

	return true;
}
//-----------------------------------------------------------------init
bool Renderer::init()
{
	//initialize DirectX
	if(!initDX())
		return false;

//NO
	//create the color buffer
	if(!colorBuffer.create(D3Ddevice, true))
		return false;

	// create the texture buffer
	if(!textureBuffer.create(D3Ddevice, true))
		return false;

	//set the default view
	//setViewPosition(0, 0);

	//set the default projection
	D3DVIEWPORT9 kViewport;
	D3Ddevice->GetViewport(&kViewport);

	float fViewWidth = static_cast<float>(kViewport.Width);
	float fViewHeight = static_cast<float>(kViewport.Height);

	float aspectRatio = (float) kViewport.Width / kViewport.Height;

	D3DXMATRIX kProjMatrix;
	D3DXMatrixPerspectiveFovLH(&kProjMatrix, D3DX_PI/4, aspectRatio, 0.1f, 2000.0f);
	D3Ddevice->SetTransform(D3DTS_PROJECTION, &kProjMatrix);

	//set the default render states
	D3Ddevice->SetRenderState(D3DRS_LIGHTING, TRUE);
	D3Ddevice->SetRenderState(D3DRS_ZENABLE, TRUE);
	D3Ddevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
	D3Ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
	D3Ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
	D3Ddevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE);
	D3Ddevice->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(50, 50, 50));//ADDED

	return true;
}
//-----------------------------------------------------------------
void Renderer::clear(void)
{
	D3Ddevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255),1.0f,0);
	D3Ddevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);//ADDED
}
//-----------------------------------------------------------------
void Renderer::beginScene(void)
{
	HRESULT hr = D3Ddevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,64,128), 1.0f, 0);
	D3Ddevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);//ADDED
	hr = D3Ddevice->BeginScene();
}
//-----------------------------------------------------------------endScene
void Renderer::endScene(void)
{
	HRESULT hr = D3Ddevice->EndScene();
	hr = D3Ddevice->Present(NULL,NULL,NULL,NULL);
}
//-----------------------------------------------------------------present
void Renderer::present(void){D3Ddevice->Present(NULL,NULL,NULL,NULL);}

//-----------------------------------------------------------------draw(Color)
void Renderer::draw(const ColorVertex* vertexCollection, 
					PrimitiveType prim, unsigned int uiVertexCount)
{
	colorBuffer.bind();
	colorBuffer.draw(vertexCollection, 
						static_cast<D3DPRIMITIVETYPE>(prim), 
						uiVertexCount);
}

//-----------------------------------------------------------------draw(Textr)
void Renderer::draw(const TextureVertex* pakVertices, 
				    PrimitiveType ePrim, unsigned int uiVertexCount)
{
	textureBuffer.bind();
	textureBuffer.draw(pakVertices, 
						static_cast<D3DPRIMITIVETYPE>(ePrim), 
						uiVertexCount);
}
//-----------------------------------------------------------------setMatrixode
void Renderer::setMatrixMode(MatrixMode eMode){m_eCurrentMatMode = eMode;};
//-----------------------------------------------------------------
void Renderer::setTransform(MatrixMode mm, D3DXMATRIX mat)//ADDED
{
	D3DTRANSFORMSTATETYPE eMatMode = static_cast<D3DTRANSFORMSTATETYPE>(m_eCurrentMatMode);
	D3Ddevice->SetTransform(D3DTS_VIEW, &mat);
}
//-----------------------------------------------------------------loadIdentity
void Renderer::loadIdentity ()
{
	D3DXMATRIX kTempMatrix;

	//set identity matrix
	D3DXMatrixIdentity(&kTempMatrix);
/*
	//if it is a view matrix, use default values
	if (m_eCurrentMatMode == VIEW) {
		
		D3DXVECTOR3 kEyePos(0,0,-1);
		D3DXVECTOR3 kLookPos(0,0,0);
		D3DXVECTOR3 kUpVector(0,1,0);
		
		//generate the view matrix
		D3DXMatrixLookAtLH(&kTempMatrix, &kEyePos, &kLookPos, &kUpVector);
	}
*/	
	//convert from MatrixMode to D3DTRANSFORMSTATETYPE
	D3DTRANSFORMSTATETYPE eMatMode = static_cast<D3DTRANSFORMSTATETYPE>(m_eCurrentMatMode);
	
	//set the matrix
	D3Ddevice->SetTransform(eMatMode, &kTempMatrix);
}
//-----------------------------------------------------------------translate
void Renderer::translate (float fX, float fY, float fZ)
{
	D3DXMATRIX kTempMatrix;

	//generate translation matrix
	D3DXMatrixTranslation(&kTempMatrix, fX,  fY, 1.0f);

	//convert from MatrixMode to D3DTRANSFORMSTATETYPE
	D3DTRANSFORMSTATETYPE eMatMode = static_cast<D3DTRANSFORMSTATETYPE>(m_eCurrentMatMode);

	//set the matrix
	D3Ddevice->MultiplyTransform(eMatMode, &kTempMatrix);
}
//-----------------------------------------------------------------rotateZ
void Renderer::rotateX (float fAngle)
{
	D3DXMATRIX kTempMatrix;

	//generate translation matrix
	D3DXMatrixRotationX(&kTempMatrix, fAngle);

	//convert from MatrixMode to D3DTRANSFORMSTATETYPE
	D3DTRANSFORMSTATETYPE eMatMode = static_cast<D3DTRANSFORMSTATETYPE>(m_eCurrentMatMode);

	//set the matrix
	D3Ddevice->MultiplyTransform(eMatMode, &kTempMatrix);
}
//-----------------------------------------------------------------rotateZ
void Renderer::rotateY (float fAngle)
{
	D3DXMATRIX kTempMatrix;

	//generate translation matrix
	D3DXMatrixRotationY(&kTempMatrix, fAngle);

	//convert from MatrixMode to D3DTRANSFORMSTATETYPE
	D3DTRANSFORMSTATETYPE eMatMode = static_cast<D3DTRANSFORMSTATETYPE>(m_eCurrentMatMode);

	//set the matrix
	D3Ddevice->MultiplyTransform(eMatMode, &kTempMatrix);
}
//-----------------------------------------------------------------rotateZ
void Renderer::rotateZ (float fAngle)
{
	D3DXMATRIX kTempMatrix;

	//generate translation matrix
	D3DXMatrixRotationZ(&kTempMatrix, fAngle);

	//convert from MatrixMode to D3DTRANSFORMSTATETYPE
	D3DTRANSFORMSTATETYPE eMatMode = static_cast<D3DTRANSFORMSTATETYPE>(m_eCurrentMatMode);

	//set the matrix
	D3Ddevice->MultiplyTransform(eMatMode, &kTempMatrix);
}
//-----------------------------------------------------------------scale
void Renderer::scale (float fW, float fH, float fD)
{
	D3DXMATRIX kTempMatrix;

	//generate translation matrix
	D3DXMatrixScaling(&kTempMatrix, fW, fH, fD);

	//convert from MatrixMode to D3DTRANSFORMSTATETYPE
	D3DTRANSFORMSTATETYPE eMatMode = static_cast<D3DTRANSFORMSTATETYPE>(m_eCurrentMatMode);

	//set the matrix
	D3Ddevice->MultiplyTransform(eMatMode, &kTempMatrix);
}
//-----------------------------------------------------------------setViewPosition
void Renderer::setViewPosition(float fPosX, float fPosY) 
{
	D3DXMATRIX kMatrix;
	D3DXVECTOR3 kEyePos;
	D3DXVECTOR3 kLookPos;
	D3DXVECTOR3 kUpVector;

	kEyePos.x = fPosX;	kEyePos.y = fPosY;	kEyePos.z = -700.0f;
	kLookPos.x = fPosX;	kLookPos.y = fPosY;	kLookPos.z = 0.0f;
	kUpVector.x = 0.0f;	kUpVector.y = 1.0f;	kUpVector.z = 0.0f;

	D3DXMatrixLookAtLH(&kMatrix, &kEyePos, &kLookPos, &kUpVector);
	D3Ddevice->SetTransform(D3DTS_VIEW, &kMatrix);
}
//-----------------------------------------------------------------loadTexture
//texture managements
bool Renderer::loadTexture (Texture& tm_texture)
{
	IDirect3DTexture9* pkDXTexture = textureMap[tm_texture.getFilename()];
	D3DSURFACE_DESC kDescription;

	// if the texture is not in the map...
	if(!pkDXTexture)
	{
		// ... load it
		HRESULT hr;
		
		// load the texture
		hr = D3DXCreateTextureFromFileEx(D3Ddevice,
										tm_texture.getFilename().c_str(), 
										0, 0, 0, 0,
										D3DFMT_UNKNOWN, D3DPOOL_MANAGED,
										D3DX_FILTER_NONE, D3DX_FILTER_NONE,
										tm_texture.getColorkey(),
										NULL,
										NULL,
										&pkDXTexture);

		if (hr != D3D_OK)
			return false;

		// add to map
		textureMap[tm_texture.getFilename()] = pkDXTexture;
	}

	pkDXTexture->GetLevelDesc(0,&kDescription);

	// set the properties
	tm_texture.setWidth(kDescription.Width);
	tm_texture.setHeight(kDescription.Height);

	return true;
}
//-----------------------------------------------------------------unbindTexture
void Renderer::unbindTexture ()
{
	D3Ddevice->SetTexture(0, NULL);
}
//-----------------------------------------------------------------bindTexture
bool Renderer::bindTexture (Texture& tm_texture)
{
	std::map<std::string, IDirect3DTexture9*>::iterator iter;
	iter = textureMap.find(tm_texture.getFilename());

	IDirect3DTexture9* pkDXTexture = NULL;

	if(iter == textureMap.end())
	{
		loadTexture(tm_texture);
	}

	pkDXTexture = textureMap[tm_texture.getFilename()];

	//bind the texture
	HRESULT hr = D3Ddevice->SetTexture(0, pkDXTexture);

	return true;
}
//-----------------------------------------------------------------setCullMode
void Renderer::setCullMode(D3DCULL mode)
{
	D3Ddevice->SetRenderState(D3DRS_CULLMODE, mode);
}
//-----------------------------------------------------------------
void Renderer::initLight()
{
	D3DLIGHT9 wn_light;
	D3DMATERIAL9 wn_material;
	 
	ZeroMemory(&wn_light, sizeof(wn_light));
    wn_light.Type = D3DLIGHT_DIRECTIONAL;
    wn_light.Diffuse = D3DXCOLOR(0.5f, 0.5f, 0.5f, 1.0f);
    wn_light.Direction = D3DXVECTOR3(-1.0f, -0.3f, -1.0f);

    D3Ddevice->SetLight(0, &wn_light);
    D3Ddevice->LightEnable(0, TRUE);

	ZeroMemory(&wn_material, sizeof(D3DMATERIAL9));
    wn_material.Ambient = D3DXCOLOR(2.0f, 2.0f, 2.0f, 2.0f);
    wn_material.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
	wn_material.Specular = D3DXCOLOR(2.0f, 2.0f, 2.0f, 2.0f);

    D3Ddevice->SetMaterial(&wn_material);
}
//-----------------------------------------------------------------constr
//constructer & deconstructer
Renderer::Renderer(HWND hWnd):
D3Dobject(NULL),
D3Ddevice(NULL),
m_hWnd(hWnd),
m_eCurrentMatMode(VIEW) 
{}
//-----------------------------------------------------------------desconst
Renderer::~Renderer(void){}

//-----------------------------------------------------------------
void Renderer::Bind(myd::Vertexbuffer<TextureVertex,(2|256|(0))> &VB)
{
	
}
//-----------------------------------------------------------------
void Renderer::CreateVB()
{
}